package com.yc.cn.ycrecycleviewlib.select;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.yc.cn.ycrecycleviewlib.R;


/**
 * <pre>
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2017/05/09
 *     desc  : 自定义RecyclerView
 *     revise:
 * </pre>
 */
public class SelectRecyclerView extends RecyclerView {


    private static final int AUTO_SCROLL_DELAY = 25;
    private int lastDraggedIndex = -1;
    private SelectAdapter<?> adapter;
    private int initialSelection;
    private boolean dragSelectActive;
    private int minReached;
    private int maxReached;
    private int hotspotHeight;
    private int hotspotOffsetTop;
    private int hotspotOffsetBottom;
    private int hotspotTopBoundStart;
    private int hotspotTopBoundEnd;
    private int hotspotBottomBoundStart;
    private int hotspotBottomBoundEnd;
    private int autoScrollVelocity;

    private boolean inTopHotspot;
    private boolean inBottomHotspot;
    private FingerListener fingerListener;

    private Handler mHandler;
    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            if (mHandler == null) {
                return;
            }
            if (inTopHotspot) {
                scrollBy(0, -autoScrollVelocity);
                mHandler.postDelayed(this, AUTO_SCROLL_DELAY);
            } else if (inBottomHotspot) {
                scrollBy(0, autoScrollVelocity);
                mHandler.postDelayed(this, AUTO_SCROLL_DELAY);
            }
        }
    };


    public SelectRecyclerView(Context context) {
        super(context);
        init(context, null);
    }

    public SelectRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public SelectRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mHandler!=null){
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
    }

    private void init(Context context, AttributeSet attrs) {
        mHandler = new Handler();
        final int defaultHotspotHeight = context.getResources().getDimensionPixelSize(R.dimen.spotHeight);
        if (attrs != null) {
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SelectRecyclerView, 0, 0);
            try {
                boolean autoScrollEnabled = a.getBoolean(R.styleable.SelectRecyclerView_scrollEnabled, true);
                if (!autoScrollEnabled) {
                    hotspotHeight = -1;
                    hotspotOffsetTop = -1;
                    hotspotOffsetBottom = -1;
                } else {
                    hotspotHeight = a.getDimensionPixelSize(R.styleable.SelectRecyclerView_spotHeight, defaultHotspotHeight);
                    hotspotOffsetTop = a.getDimensionPixelSize(R.styleable.SelectRecyclerView_spot_offsetTop, 0);
                    hotspotOffsetBottom = a.getDimensionPixelSize(R.styleable.SelectRecyclerView_spot_offsetBottom, 0);
                }
            } finally {
                a.recycle();
            }
        } else {
            hotspotHeight = defaultHotspotHeight;
        }
    }

    public void setFingerListener(@Nullable FingerListener listener) {
        this.fingerListener = listener;
    }

    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        super.onMeasure(widthSpec, heightSpec);
        if (hotspotHeight > -1) {
            hotspotTopBoundStart = hotspotOffsetTop;
            hotspotTopBoundEnd = hotspotOffsetTop + hotspotHeight;
            hotspotBottomBoundStart = (getMeasuredHeight() - hotspotHeight) - hotspotOffsetBottom;
            hotspotBottomBoundEnd = getMeasuredHeight() - hotspotOffsetBottom;
        }
    }

    public boolean setDragSelectActive(boolean active, int initialSelection) {
        if (active && dragSelectActive) {
            return false;
        }
        lastDraggedIndex = -1;
        minReached = -1;
        maxReached = -1;
        adapter.setSelected(initialSelection, true);
        dragSelectActive = active;
        this.initialSelection = initialSelection;
        lastDraggedIndex = initialSelection;
        if (fingerListener != null) {
            fingerListener.onDragSelectFingerAction(true);
        }
        return true;
    }


    @Override
    @Deprecated
    public void setAdapter(Adapter adapter) {
        if (!(adapter instanceof SelectAdapter<?>)) {
            throw new IllegalArgumentException("Adapter must be a SelectAdapter.");
        }
        setAdapter((SelectAdapter<?>) adapter);
    }

    public void setAdapter(SelectAdapter<?> adapter) {
        super.setAdapter(adapter);
        this.adapter = adapter;
    }


    private int getItemPosition(MotionEvent e) {
        final View v = findChildViewUnder(e.getX(), e.getY());
        if (v == null) {
            return NO_POSITION;
        }
        if (v.getTag() == null || !(v.getTag() instanceof ViewHolder)) {
            throw new IllegalStateException("Make sure your adapter makes " +
                    "a call to super.onBindViewHolder(), and doesn't override itemView tags.");
        }
        final ViewHolder holder = (ViewHolder) v.getTag();
        return holder.getAdapterPosition();
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        if (adapter.getItemCount() == 0) {
            return super.dispatchTouchEvent(e);
        }
        if (dragSelectActive) {
            final int itemPosition = getItemPosition(e);
            boolean isDispatch = false;
            switch (e.getAction()){
                case MotionEvent.ACTION_UP:
                    dragSelectActive = false;
                    inTopHotspot = false;
                    inBottomHotspot = false;
                    mHandler.removeCallbacks(mRunnable);
                    if (fingerListener != null) {
                        fingerListener.onDragSelectFingerAction(false);
                    }
                    isDispatch = true;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (hotspotHeight > -1) {
                        if (e.getY() >= hotspotTopBoundStart && e.getY() <= hotspotTopBoundEnd) {
                            inBottomHotspot = false;
                            if (!inTopHotspot) {
                                inTopHotspot = true;
                                mHandler.removeCallbacks(mRunnable);
                                mHandler.postDelayed(mRunnable, AUTO_SCROLL_DELAY);
                            }
                            final float simulatedFactor = hotspotTopBoundEnd - hotspotTopBoundStart;
                            final float simulatedY = e.getY() - hotspotTopBoundStart;
                            autoScrollVelocity = (int) (simulatedFactor - simulatedY) / 2;
                        } else if (e.getY() >= hotspotBottomBoundStart && e.getY() <= hotspotBottomBoundEnd) {
                            inTopHotspot = false;
                            if (!inBottomHotspot) {
                                inBottomHotspot = true;
                                mHandler.removeCallbacks(mRunnable);
                                mHandler.postDelayed(mRunnable, AUTO_SCROLL_DELAY);
                            }
                            final float simulatedY = e.getY() + hotspotBottomBoundEnd;
                            final float simulatedFactor = hotspotBottomBoundStart + hotspotBottomBoundEnd;
                            autoScrollVelocity = (int) (simulatedY - simulatedFactor) / 2;
                        } else if (inTopHotspot || inBottomHotspot) {
                            mHandler.removeCallbacks(mRunnable);
                            inTopHotspot = false;
                            inBottomHotspot = false;
                        }
                    }

                    if (itemPosition != NO_POSITION && lastDraggedIndex != itemPosition) {
                        lastDraggedIndex = itemPosition;
                        if (minReached == -1) {
                            minReached = lastDraggedIndex;
                        }
                        if (maxReached == -1) {
                            maxReached = lastDraggedIndex;
                        }
                        if (lastDraggedIndex > maxReached) {
                            maxReached = lastDraggedIndex;
                        }
                        if (lastDraggedIndex < minReached) {
                            minReached = lastDraggedIndex;
                        }
                        if (initialSelection == lastDraggedIndex) {
                            minReached = lastDraggedIndex;
                            maxReached = lastDraggedIndex;
                        }
                    }
                    isDispatch = true;
                    break;
                default:
                    break;
            }
            return isDispatch;
        }
        return super.dispatchTouchEvent(e);
    }
}
